package com.yanqu.road.server.manger.activity.recycle;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.activity.ActivityItemRecycleData;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.OpenGoodsBagResult;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eMailType;
import com.yanqu.road.entity.player.UserBagItem;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.logic.bussiness.player.UserBagBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.player.BagModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.manger.MultipleLanguageMgr;
import com.yanqu.road.server.manger.ServerLanguageMgr;
import com.yanqu.road.server.manger.config.GoodsBagMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigInteger;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

public abstract class AbstractItemRecycleStrategy {
    protected static final long gapTime = 600 * 1000L;
    protected final Logger log = LogManager.getLogger(this.getClass().getName());

    protected int activityType;

    public abstract void markNeedRecycleItem();

    public AbstractItemRecycleStrategy() {
        initActivityType();
    }

    protected abstract void initActivityType();

    public void recycleItem() {
        Map<Integer, List<ActivityItemRecycleData>> batchRecycleItemMap = ActivityItemRecycleMgr.getNeedRecycleItemByActivityType(activityType);
        int hours = DateHelper.getHours();
        if (hours == 0) {
            // 0 点不回收
            return;
        }
        Calendar rightNow = Calendar.getInstance();
        int minute = rightNow.get(Calendar.MINUTE);
        for (List<ActivityItemRecycleData> dataList : batchRecycleItemMap.values()) {
            for (ActivityItemRecycleData data : dataList) {
                for (UserInfo userInfo : UserMgr.getUserInfoList()) {
                    //判断是否在线 不在线只读取最近一星期登录的玩家
                    GamePlayer player = GamePlayerMgr.getOnlinePlayer(userInfo.getUserId());
                    boolean needDeal = false;
                    if (player != null) {
                        needDeal = true;
                    }else {
                        long lastLoginTime = userInfo.getLastLoginTime();
                        boolean isOfflineRecycleTime = hours >= 2 && hours < 6;
                        if (System.currentTimeMillis() / 1000 - lastLoginTime < 7 * DateHelper.DAY_SECONDS && isOfflineRecycleTime && minute < 3) {
                            //离线玩家只在 凌晨 2 - 6 点之间回收
                            needDeal = true;
                        }
                    }
                    if (needDeal) {
                        try {
                            Object saveLock = GamePlayerMgr.getPlayerLock(userInfo.getUserId());
                            synchronized (saveLock) {
                                doRecycle(userInfo.getUserId(), data);
                            }
                        } catch (Exception e) {
                            ActivityItemRecycleMgr.getLogger().error(" user: {} recycle item: {} error.",userInfo.getUserId(), JSON.toJSONString(data),e);
                        }
                    }
                }
                ActivityItemRecycleMgr.endItemRecycle(data);
            }
        }

    }


    protected UserBagItem getUserBagItem(long userId, int itemId) {
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
        if (player != null) {
            return player.getModule(BagModule.class).getUserBagItem(itemId);
        }
        Map<Integer, UserBagItem> userBagItemMap = UserBagBussiness.getUserBagItemMap(userId);
        if (userBagItemMap != null) {
            return userBagItemMap.get(itemId);
        }
        return null;
    }

    protected boolean clearUserBagItems(long userId, int goodType){
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
        Map<Integer, UserBagItem> userBagItemMap;
        if (player != null) {
            userBagItemMap =  player.getModule(BagModule.class).getUserBagItemMap();
        }else {
            userBagItemMap = UserBagBussiness.getUserBagItemMap(userId);
        }
        if(userBagItemMap == null || userBagItemMap.isEmpty()){
            return false;
        }
        List<UserBagItem> itemList = new ArrayList<>();
        for (Map.Entry<Integer, UserBagItem> entry : userBagItemMap.entrySet()) {
            UserBagItem bagItem = entry.getValue();
            if(bagItem.getNum() <= 0){
                continue;
            }
            GoodsInfo goodsInfo = GoodsMgr.getGoodsById(bagItem.getGoodsId());
            if(goodsInfo == null || goodsInfo.getType() != goodType){
                continue;
            }
            itemList.add(bagItem);
        }
        for (UserBagItem bagItem : itemList) {
            long num = bagItem.getNum();
            player = GamePlayerMgr.getOnlinePlayer(userId);
            log.info("userId : {} 回收道具 {}， 数量： {}", userId, bagItem.getGoodsId(),num);
            if (player != null) {
                return player.getModule(CurrencyModule.class).removeCurrency(new Property(bagItem.getGoodsId(), BigInteger.valueOf(bagItem.getNum())), eLogMoneyType.Activity, eLogMoneyType.ActivityItemRecycle);
            } else {
                bagItem.setNum(0);
                boolean success = UserBagBussiness.updateUserBagItem(bagItem);
                if (success) {
                    long vipExp = 0;
                    UserInfo userInfo = UserMgr.getUserInfo(userId);
                    if (userInfo != null) {
                        vipExp = userInfo.getVipExp();
                    }
                    LogMgr.addLogGoods(bagItem.getGoodsId(), userId, false, num, 0, eLogMoneyType.ActivityItemRecycle, vipExp);
                }
            }
        }
        return true;
    }

    protected boolean removeItem(UserBagItem bagItem) {
        if (bagItem == null || bagItem.getNum() <= 0) {
            return false;
        }
        long userId = bagItem.getUserId();
        long num = bagItem.getNum();
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
        log.info("userId : {} 回收道具 {}， 数量： {}", userId, bagItem.getGoodsId(),num);
        if (player != null) {
            return player.getModule(CurrencyModule.class).removeCurrency(new Property(bagItem.getGoodsId(), BigInteger.valueOf(bagItem.getNum())), eLogMoneyType.Activity, eLogMoneyType.ActivityItemRecycle);
        } else {
            bagItem.setNum(0);
            boolean success = UserBagBussiness.updateUserBagItem(bagItem);
            if (success) {
                long vipExp = 0;
                UserInfo userInfo = UserMgr.getUserInfo(userId);
                if (userInfo != null) {
                    vipExp = userInfo.getVipExp();
                }
                LogMgr.addLogGoods(bagItem.getGoodsId(), userId, false, num, 0, eLogMoneyType.ActivityItemRecycle, vipExp);
            }
            return success;
        }
    }


    protected abstract void doRecycle(long userId, ActivityItemRecycleData data);

    protected void item2Score(long userId, ActivityItemRecycleData data, String mailTitleKey, String mailContentKey) {

        int itemId = data.getItemId();
        Property reward;
        GoodsInfo goodsInfo;
        GoodsInfo scoreGoodsInfo;
        UserBagItem userBagItem = getUserBagItem(userId, itemId);
        if (userBagItem == null || userBagItem.getNum() <= 0) {
            return;
        }
        goodsInfo = GoodsMgr.getGoodsById(itemId);
        long count = userBagItem.getNum();
        if (null == goodsInfo) {
            log.error("remove  activity goods to score error,goods no found,goodsId:{},remove count:{}", itemId, userBagItem.getNum());
            return;
        }
        List<String> paramList = data.getParamList();
        int scoreGoodsId = Integer.parseInt(paramList.get(1));
        scoreGoodsInfo = GoodsMgr.getGoodsById(scoreGoodsId);
        if (null == scoreGoodsInfo) {
            log.error("remove  activity goods to score error, score goods no found,goodsId:{},remove count:{}", itemId, count);
            return;
        }
        int scoreParamIndex = Integer.parseInt(paramList.get(2));
        BigInteger score = goodsInfo.getParamList().get(scoreParamIndex);       //参数x为转换积分
        if (score.compareTo(BigInteger.ZERO) <= 0) {
            log.warn("remove  activity goods to score error,goodsId:{},remove count:{}", itemId, count);
            return;
        }
        String activityName = paramList.get(3);
        score = score.multiply(BigInteger.valueOf(count));
        reward = new Property(scoreGoodsId, score);
        String rewardStr = PropertyHelper.parsePropertyToString(reward);
        String language = UserMgr.getUserInfo(userId).getLanguage();
        if (removeItem(userBagItem)) {
            if (!StringUtils.isNullOrEmpty(rewardStr)) {//有将道具转换
                String goodsName = ServerLanguageMgr.getContent(goodsInfo.getGoodsName(), language);
                activityName = ServerLanguageMgr.getContent(activityName, language);
                String scoreName = ServerLanguageMgr.getContent(scoreGoodsInfo.getGoodsName(), language);
                if(scoreGoodsId == GameConfig.GAME_MONEY_INGOTS){
                    //元宝多语言、特殊处理
                    scoreName = MultipleLanguageMgr.getContent(scoreGoodsInfo.getGoodsName(), language);
                }
                String mailTitle = StringUtils.format(MultipleLanguageMgr.getContent(mailTitleKey,
                        language), activityName);
                String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(mailContentKey,
                        language), activityName, goodsName, count, scoreName);
                MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), rewardStr, mailContent, mailTitle);
            } else {
                if (count > 0) {
                    log.warn("remove  activity goods to score reward is empty,consume goodsId:{},count:{}", itemId, count);
                }
            }
        }
    }

    /**
     * 这里的道具转兑换积分,每单位积分值为回收道具的goodsInfo.getParamList().get(scoreParamIndex), scoreParamIndex为data.getParamList().get(2)
     */
    protected void item2Score(long userId, ActivityItemRecycleData data) {
        String titleKey = MailManager.ACTIVITY_GOODS_AUTO_CONSUME_TITLE;
        String contentKey = MailManager.ACTIVITY_GOODS_AUTO_CONSUME_CONTENT;
        item2Score(userId, data, titleKey, contentKey);
    }

    public abstract boolean isActivityRunning();

    /**
     * 这里的道具转兑换积分,每单位积分值为data.getParamList().get(2)
     */
    protected void item2ScoreEx(long userId, ActivityItemRecycleData data) {
        String titleKey = MailManager.ACTIVITY_GOODS_AUTO_CONSUME_TITLE;
        String contentKey = MailManager.ACTIVITY_GOODS_AUTO_CONSUME_CONTENT;
        item2ScoreEx(userId, data, titleKey, contentKey);
    }

    /**
     * 道具回收转换积分,道具对应的积分为data.getParamList().get(2)
     */
    protected void item2ScoreEx(long userId, ActivityItemRecycleData data, String mailTitleKey, String mailContentKey) {

        int itemId = data.getItemId();
        Property reward;
        GoodsInfo goodsInfo;
        GoodsInfo scoreGoodsInfo;
        UserBagItem userBagItem = getUserBagItem(userId, itemId);
        if (userBagItem == null || userBagItem.getNum() <= 0) {
            return;
        }
        goodsInfo = GoodsMgr.getGoodsById(itemId);
        long count = userBagItem.getNum();
        if (null == goodsInfo) {
            log.error("remove  activity goods to score error,goods no found,goodsId:{},remove count:{}", itemId, userBagItem.getNum());
            return;
        }
        List<String> paramList = data.getParamList();
        int scoreGoodsId = Integer.parseInt(paramList.get(1));
        scoreGoodsInfo = GoodsMgr.getGoodsById(scoreGoodsId);
        if (null == scoreGoodsInfo) {
            log.error("remove  activity goods to score error, score goods no found,goodsId:{},remove count:{}", itemId, count);
            return;
        }

        BigInteger score = new BigInteger(paramList.get(2));
        if (score.compareTo(BigInteger.ZERO) <= 0) {
            log.warn("remove  activity goods to score error,goodsId:{},remove count:{}", itemId, count);
            return;
        }
        String activityName = paramList.get(3);
        score = score.multiply(BigInteger.valueOf(count));
        reward = new Property(scoreGoodsId, score);
        String rewardStr = PropertyHelper.parsePropertyToString(reward);
        String language = UserMgr.getUserInfo(userId).getLanguage();
        if (removeItem(userBagItem)) {
            if (!StringUtils.isNullOrEmpty(rewardStr)) {//有将道具转换
                String goodsName = ServerLanguageMgr.getContent(goodsInfo.getGoodsName(), language);
                activityName = ServerLanguageMgr.getContent(activityName, language);
                String scoreName = ServerLanguageMgr.getContent(scoreGoodsInfo.getGoodsName(), language);
                if(scoreGoodsId == GameConfig.GAME_MONEY_INGOTS){
                    //元宝多语言、特殊处理
                    scoreName = MultipleLanguageMgr.getContent(scoreGoodsInfo.getGoodsName(), language);
                }
                String mailTitle = StringUtils.format(MultipleLanguageMgr.getContent(mailTitleKey,
                        language), activityName);
                String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(mailContentKey,
                        language), activityName, goodsName, count, scoreName);
                MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), rewardStr, mailContent, mailTitle);
            } else {
                if (count > 0) {
                    log.warn("remove  activity goods to score reward is empty,consume goodsId:{},count:{}", itemId, count);
                }
            }
        }
    }

    /**
     * 礼包类型道具回收，帮玩家使用掉
     * @param userId 玩家ID
     * @param itemId 道具ID
     * @param activityName 活动名称
     */
    protected void useGiftItem(long userId, int itemId, String activityName) {
        //奖励
        Property reward = new Property();
        //获取道具
        UserBagItem bagItem = getUserBagItem(userId, itemId);
        if (bagItem != null) {
            long goodsNum = bagItem.getNum();
            for (int i = 0; i < goodsNum; i++) {
                OpenGoodsBagResult result = GoodsBagMgr.getRandomGoods(bagItem.getGoodsId());
                reward.addProperty(result.getReward());
            }
            //remove掉
            boolean flag = removeItem(bagItem);
            //邮件发送奖励
            String language = UserMgr.getUserInfo(userId).getLanguage();
            activityName = ServerLanguageMgr.getContent(activityName, language);
            String goodsName = "";
            GoodsInfo goodsInfo = GoodsMgr.getGoodsById(itemId);
            if (null != goodsInfo) {
                goodsName = ServerLanguageMgr.getContent(goodsInfo.getGoodsName(), language);
            } else {
                log.error("remove common activity goods to score,goods no find,goodsId:{},remove count:{}", itemId, goodsNum);
            }
            if (flag) {
                String mailTitle = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.COMMON_ACTIVITY_GOODS_AUTO_CONSUME_TITLE, language),
                        activityName);
                String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.COMMON_ACTIVITY_GOODS_AUTO_CONSUME_CONTENT, language),
                        activityName, goodsName, goodsNum);
                MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), PropertyHelper.parsePropertyToString(reward), mailContent, mailTitle);
            }
        }
    }

    /**
     * 回收道具，并发放指定奖励
     * @param userId
     * @param bagItem
     * @param activityName
     * @param reward
     */
    protected void removeItemAndSendReward(long userId, UserBagItem bagItem, String activityName, Property reward) {
        //获取道具
        if (bagItem != null) {
            int goodsId = bagItem.getGoodsId();
            long goodsNum = bagItem.getNum();
            //remove掉
            boolean flag = removeItem(bagItem);
            //邮件发送奖励
            String language = UserMgr.getUserInfo(userId).getLanguage();
            activityName = ServerLanguageMgr.getContent(activityName, language);
            String goodsName = "";
            GoodsInfo goodsInfo = GoodsMgr.getGoodsById(goodsId);
            if (null != goodsInfo) {
                goodsName = ServerLanguageMgr.getContent(goodsInfo.getGoodsName(), language);
            } else {
                log.error("回收道具，并发放指定奖励， activity goods to score,goods no find,goodsId:{},remove count:{}", goodsId, goodsNum);
            }
            if (flag) {
                String mailTitle = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.COMMON_ACTIVITY_GOODS_AUTO_CONSUME_TITLE, language),
                        activityName);
                String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.COMMON_ACTIVITY_GOODS_AUTO_CONSUME_CONTENT, language),
                        activityName, goodsName, goodsNum);
                MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), PropertyHelper.parsePropertyToString(reward), mailContent, mailTitle);
            }
        }
    }

    /**
     * 测试用的,不要乱用
     */
    public void testRecycle() {
        for (UserInfo userInfo : UserMgr.getUserInfoList()) {
            List<ActivityItemRecycleData> recycleDataList = ActivityItemRecycleMgr.testGetNeedRecycleItemByActivityType(activityType);
            for (ActivityItemRecycleData data : recycleDataList) {
                doRecycle(userInfo.getUserId(), data);
            }
        }
    }

    public int getActivityType() {
        return activityType;
    }
}
